Il controllo Winsock ed il protocollo TCP

 

Introduzione: Quale protocollo utilizzare.

Utilizzando il controllo Winsock è possibile mettere in comunicazione due computer sfruttando il protocollo
TCP o UDP.
Quale protocollo utilizzare? Citando Microsoft come fonte:

"[...] Il protocollo TCP (Transfer Control Protocol) consente di creare e mantenere una connessione con un
computer remoto. Utilizzando la connessione, entrambi i computer possono inviare e ricevere dati. [...] Il
protocollo TCP è un protocollo basato sulla connessione ed è analogo ad un telefono, in quanto l'utente
deve stabilire una connessione prima di poter procedere [...]
Il protocollo UDP (User Datagram Protocol) è un protocollo senza connessione. A differenza del TCP, non
viene stabilita alcuna connessione tra i computer [...] e la transazione tra due computer è analoga al
passaggio di un messaggio che viene inviato da un computer all'altro senza che venga stabilita una
connessione esplicita tra i due computer. La dimensione massima dei dati che è possibile inviare in
ciascuna trasmissione dipende della rete [...].
Le applicazioni UDP possono essere applicazioni client o server.[...]".

In particolare, prendendo TCP come protocollo di riferimento, nel momento in cui i due computer sono in
comunicazione, essi ricoprono dei ruoli ben definiti.
Il computer Server invia i dati a chi ne fa richiesta utilizzando la porta specificata mentre il computer Client
esegue tale richiesta.
L'operazione che avviene tra Client e Server è riassumibile in cinque punti fondamentali:

·

il computer Server è in attesa di richieste di comunicazione sulla porta indicata;

·

il computer Client richiede al Server l'autorizzazione ad iniziare una comunicazione;

·

una volta accettata la richiesta del Client, il computer Server invia i dati;

·

terminato lo scambio di dati la comunicazione viene chiusa;

·

il computer Server torna in uno stato di attesa di eventuali richieste di comunicazione sulla

porta indicata.

1: Le impostazioni TCP/IP.

Impostazioni TCP/IP

Prima di tutto, ad ogni modo, è necessario conoscere se le impostazioni TCP/IP del proprio computer sono corrette. Si tratta, principalmente, di scrupolo e di curiosità, perché settaggi errati provocherebbero maggiori disagi rispetto alla semplice impossibilità di utilizzare il controllo Winsock in un progetto Visual Basic. Se si vuole procedere al controllo, sarà necessario aprire il prompt di Dos. Una volta visualizzato il tipico schermo nero, scrivere la seguente linea:

Ping NomeComputer

dove NomeComputer rappresenta il nome oppure l'indirizzo IP del proprio computer. Impostazioni TCP/IP corrette generano una risposta da parte del DOS di questo tipo:

Figura 1

Problemi di settaggio generano invece un messaggio "host di destinazione non raggiungibile", oltre all'avvertimento che dei pacchetti di dati inviati nessuno è tornato indietro, ma sono andati tutti persi. E' inoltre possibile ricevere un messaggio del tipo:

Figura 2

il quale indica che è stato indicato un nome oppure un indirizzo IP non corretto del computer sul quale è stata eseguita la prova. Nel caso in cui il nome del proprio computer o dell'indirizzo IP ci risulti del tutto sconosciuto, si può aprire un nuovo progetto EXE Standard, inserire un controllo Winsock sulla form (operazioni che verranno comunque analizzate in dettaglio poco più avanti) ed aggiungere nel modulo di codice di Form1 il seguente segmento di codice:

Private Sub

MsgBox Winsock1.LocalHostName End Sub

Avviando l'applicazione si riceverà una finestra di messaggio recante il nome del proprio computer. La stessa cosa può essere fatta nel caso si voglia sapere l'identificativo IP:

Private Sub

MsgBox Winsock1.LocalIP End Sub

Generalmente, la cosa migliore è utilizzare il nome del computer più che l'indirizzo IP, a meno che non si sia decisamente certi che questo non cambierà mai (come nel caso dell'applicazione che andremo a sviluppare tra poco che, operando in locale, non richiede l'assegnazione di un indirizzo IP differente da quello indicato dalla finestra di messaggio aperta poco fa). Prima di cominciare a dare uno sguardo ad un progetto di esempio, sarà necessario premettere che le applicazioni distribuite dovranno in ogni caso fare riferimento al file MSWINSCK.OCX, quindi si dovrà provvedere a fornirlo con l'applicazione se si vuole essere sicuri che tutti ne possano fare uso. Un'ultima premessa: come si è visto dalla prova che abbiamo fatto poc'anzi, non è assolutamente necessaria la presenza di due computer fisici differenti. Client e Server possono infatti essere il medesimo computer e dunque coesistere in esso. Dal prompt di DOS, infatti, non abbiamo fatto altro che inviarci dei pacchetti di dati e vedere se ed in quanto tempo ci sarebbero tornati indietro. La figura sottostante dovrebbe chiarire meglio il concetto.

Figura 3

E' importante anche avere un quadro generale di quali operazioni l'oggetto possa compiere per noi. Per
questo motivo riassumiamo in tre elenchi le proprietà, i metodi e gli eventi che competono a Winsock e che
gli permettono di essere manipolato in modo agevole.
Non è il caso di preoccuparsi troppo se non si riesce a comprendere in modo chiaro l'utilità di alcune
caratteristiche di Winsock: andando avanti con lo sviluppo dell'applicazione che tra poco inizieremo,
verranno utilizzate gran parte delle funzioni di cui il controllo dispone.
Questo è l'elenco delle proprietà:

Proprietà BytesReceived : corrisponde al numero di byte scambiati nell'operazione di comunicazione
Client/Server. Rappresenta dunque le dimensioni dei pacchetti di dati scambiati. Tale proprietà è associata
al metodo GetData. TIPO DI DATO: LONG;
Proprietà LocalHostName : corrisponde al nome del computer sul quale opera l'applicazione contenente il
controllo Winsock. TIPO DI DATO: STRING;
Proprietà LocalIP : corrisponde all'indirizzo del computer sul quale opera l'applicazione contenente il
controllo Winsock. TIPO DI DATO: STRING;
Proprietà LocalPort : è il numero che identifica la porta attraverso la quale verrà effettuata la
comunicazione Client/Server. E' una proprietà di lettura e scrittura anche in fase di esecuzione. In
particolare:

-per il client, questa proprietà definisce la porta locale dalla quale vengono inviati i dati; se l'applicazione non richiede una determinata porta, specificare la porta 0. Il controllo effettuerà la selezione casuale di una porta. Dopo aver stabilito la connessione, la porta locale verrà utilizzata per la connessione TCP;

-pPer il server, questa proprietà definisce la porta locale di attesa. Se viene specificata la porta 0, verrà utilizzata una porta casuale. Dopo aver richiamato il metodo Listen, la proprietà conterrà la porta selezionata.

TIPO DI DATO: LONG; Proprietà Protocol : è il tipo di protocollo che verrà utilizzato. La scelta è tra TCP ed UDP. Prima di reimpostare questa proprietà è necessario chiudere il controllo utilizzando il metodo Close. Le impostazioni di Protocol possono essere:

-sckTCPProtocol, caratterizzato dalla costante 0 che indica l'utilizzo (predefinito) del protocollo TCP;

-sckUDPProtoco,l caratterizzato dalla costante 1 che indica l'utilizzo del protocollo UDP; TIPO DI DATO val/cost ; Proprietà RemoteHost : è il nome del computer al quale ci si connette per la richiesta di scambio dati. TIPO DI DATO: STRING; Proprietà RemoteHostIP : è l'indirizzo IP del computer al quale ci si connette per la richiesta di scambio dati.

TIPO DI DATO: STRING;
Proprietà RemotePort : rappresenta la porta alla quale connettersi per richiedere i dati. Quando viene
impostata la proprietà Protocol, la proprietà RemotePort viene automaticamente impostata sulla porta
predefinita appropriata di ciascun protocollo, ossia:
-porta 80 ->HTTP, utilizzata comunemente per le connessioni al World Wide Web;
-porta 21 -> FTP
TIPO DI DATO: LONG;
Proprietà SocketHandle : è un valore corrispondente all'handle di socket utilizzato dal controllo per
comunicare con il livello Winsock. E' una proprietà di sola lettura e non disponibile in fase di progettazione.
Tale proprietà sarà utilizzata per essere passata alle API Winsock.
TIPO DI DATO: LONG;
Proprietà State : Restituisce lo stato del controllo Winsock nel momento in cui ne è richiesta la verifica. I
tipi di stato sono:

sckClosed: corrispondente al valore 0. E' l'impostazione predefinita che corrisponde allo stato 'chiuso' del
controllo;
sckOpen: corrispondente al valore 1 ed indica lo stato 'aperto' del controllo;
sckListening: corrispondente al valore 2 ed indica lo stato 'in attesa di comunicazione' del controllo;
sckConnectionPending: corrispondente al valore 3 ed indica lo stato 'comunicazione in corso' del controllo;
sckResolvingHost: corrispondente al valore 4 ed indica lo stato 'risoluzione dell'host in corso' del controllo;
sckHostResolved: corrispondente al valore 5 ed indica lo stato 'host risolto' del controllo;
sckConnecting: corrispondente al valore 6 ed indica lo stato 'aperto' del controllo;
sckConnected: corrispondente al valore 7 ed indica lo stato 'connesso' del controllo;
sckClosing: corrispondente al valore 8 ed indica che il client sta chiudendo la comunicazione;
sckError: corrispondente al valore 9 ed indica un errore in un'operazione eseguita da Winsock;
TIPO DI DATO: LONG;

La tabella dei metodi invece è la seguente:

Metodo BytesReceived : consente di accettare una richiesta di comunicazione da parte del client.
Generalmente il metodo Accept viene utilizzato nell'evento ConnectionRequest ed in una nuova istanza del
controllo Winsock anziché nel controllo in attesa;
Metodo Bind : specifica la porta locale e l'IP locale da utilizzare per le connessioni TCP. La sintassi è la
seguente: Winsock.Bind PortaLocale, IPLocale dove PortaLocale è la porta utilizzata per effettuare la
connessione e IPLocale è l'indirizzo IP locale utilizzato per effettuare la connessione;
Metodo Close : chiude la comunicazione TCP o una socket in attesa per entrambe le applicazioni client e
server;
Metodo Connect : invia una richiesta di connessione ad un computer remoto. La sintassi è la seguente:
Winsock.Connect HostRemoto, PortaRemota dove HostRemoto è il nome del computer server al quale ci si
connette e PortaRemota è la porta utilizzata;
Metodo GetData : recupera il blocco di dati corrente e lo memorizza in una variabile di tipo Variant.
La sintassi è la seguente: oggetto.GetData dati, [tipo,] [lunMax], dove dati memorizza i dati recuperati dopo
l'esecuzione del metodo. Se i dati non sono sufficienti per il tipo di richiesta, la variabile verrà impostata su
Empty. Tipo è invece il tipo di dati da recuperare. Il metodo GetData viene in genere utilizzato con l'evento
DataArrival contenente l'argomento totalBytes. Se il valore di lunMax è minore del valore dell'argomento
totalBytes, verrà visualizzato il messaggio di avviso 10040 in cui viene comunicato che i byte rimanenti
andranno perduti. Le possibili impostazioni di tipo sono le seguenti:

vbByte Byte
vbInteger Integer
vbLong Long
vbSingle Single
vbDouble Double
vbCurrency Currency
vbDate Date
vbBoolean Boolean
vbError SCODE
vbString String
vbArray + vbByte Byte Array

lunMax specifica la dimensione desiderata della matrice Byte o della stringa da ricevere. Se non viene
specificata alcuna matrice Byte o stringa in questo argomento, verranno recuperati tutti i dati disponibili. Se
viene specificato un tipo di dati diverso da una matrice Byte o una stringa, l'argomento verrà ignorato;

 

 

 

 

 

2: I Socket.

 

 

I Socket Nella Tabella precedente si è parlato di socket. Un socket, come già accennato poco fa, è un oggetto attraverso il quale un'applicazione che ne fa uso in modo specifico invia o riceve dati attraverso la rete con altri socket che fanno uso dell'IPS (Internet Protocol Suite). I socket sono bidirezionali, ossia consentono allo stesso momento un flusso di dati sia in entrata che in uscita. Esistono due tipi di socket: · Stream sockets, che consentono un flusso di dati continuo ed illimitato con la garanzia di evitare duplicazione di dati inviati; · Datagram sockets, i quali non garantiscono che l'ordine di ricezione dei dati sia lo stesso di quello di invio, col rischio di non poter evitare duplicazione di dati (cioè stessi pacchetti di dati possono arrivare a destinazione più volte).

 

Questo è l’elenco degli eventi:

Evento Close : viene generato quando il computer remoto interrompe la connessione;

Evento Connect : viene generato nel momento in cui la connessione è stata stabilita con successo;

Evento ConnectionRequest : viene generato nel momento in cui un computer client invia una richiesta di connessione. Il server può quindi decidere se accettare o meno la comunicazione. In caso di rifiuto, il client riceverà l'evento Close;

Evento DataArrival : viene generato nel momento in cui un computer client riceve dei dati. L'evento viene generato nel caso in cui tutti i nuovi dati inviati col metodo GetData siano recuperati con successo. Per evitare duplicazione di pacchetti di dati, solamente i nuovi dati saranno considerati. La sintassi è la seguente: Winsock.DataArrival (BytesTotali As Long) dove BytesTotali rappresenta il numero di dati che possono essere recuperati;

 Evento Error : viene generato nel caso in cui si verifichi un errore qualsiasi nel procedimento di connessione, di invio, di richiesta o di chiusura della connessione. La sintassi è la seguente: Winsock.Error(Numero As Integer, Descrizione As String, Scode As Long, Origine As String, HelpFile as String, HelpContext As Long, CancelDisplay As Boolean), dove Numero indica il codice dell'errore, Descrizione la descrizione dell'errore, Scode è un valore di tipo Long SCODE, Origine descrive l'origine dell'errore, HelpFile è una stringa contenente il nome del file della Guida in linea, HelpContext è il contesto della Guida in linea e CancelDisplay indica l'annullamento della visualizzazione. L'impostazione predefinita (CancelDisplay = False) permette la visualizzazione di una finestra di messaggio di errore predefinita.

Di seguito sono elencati i codici degli errori: sckOutOfMemory: corrispondente al valore 7. Descrive un errore causato dall'esaurimento della memoria; sckInvalidPropertyValue: corrisponde al valore 380 e descrive un valore della proprietà non valido; sckGetNotSupported: corrispondente al valore 394. Descrive un errore causato dall'impossibilità di leggere la proprietà; sckSetNotSupported: corrispondente al valore 383. Descrive un errore causato dall'impostazione di una proprietà che è di sola lettura; sckBadState: corrispondente al valore 40006. Protocollo o stato della connessione errato per la transazione o la richiesta; sckInvalidArg: corrispondente al valore 40014. L'argomento passato ad una funzione è in un formato errato o non è compreso nell'intervallo specificato; sckSuccess: corrispondente al valore 40017. Connessione completata; sckUnsupported: corrispondente al valore 40018. Indica un valore di tipo Variant non supportato; sckInvalidOp: corrispondente al valore 40020. Indica un'operazione non valida; sckOutOfRange: corrispondente al valore 40021. Indica un argomento non compreso nell'intervallo; consentita l'operazione che si è tentato di compiere; sckOpCanceled: corrispondente al valore 1004. L'operazione è stata annullata; sckInvalidArgument: corrispondente al valore 10014. Indica che il flag non è stato impostato; sckWouldBlock: corrispondente al valore 10035. Indica che non è possibile bloccare il socket sebbene ne sia stato specificato il blocco; sckInProgress: corrispondente al valore 10036. Indica che è in corso un'operazione Winsock di blocco; sckAlreadyComplete: corrispondente al valore 10037. Indica che l'operazione richiesta è già stata eseguita; sckNotSocked: corrispondente al valore 10038. Indica che non si fa riferimento ad un socket; sckMsgTooBig: corrispondente al valore 10040. Indica un datagramma troppo grosso per essere inserito nel buffer; sckPortNotSupported: corrispondente al valore 10043. Indica che la porta specificata non può essere utilizzata per l'operazione indicata; sckAddressInUs: corrispondente al valore 10048. Indica un indirizzo già in uso; sckAddressNotAvailable: corrispondente al valore 10049. Indica che l'indirizzo indicato del computer locale non è valido; sckNetworkSubsystemFailed: corrispondente al valore 10050. Indica un errore nel sottosistema di rete; sckNetworkUnreachable: corrispondente al valore 10051. Indica che l'host non è in grado di raggiungere la rete; sckNetReset: corrispondente al valore 10052. Indica che la connessione è stata interrotta quando è stato impostato SO_KEEPALIVE; sckConnectAborted: corrispondente al valore 10053. Indica una connessione fallita a causa di un timeout (tempo massimo di attesa superato) o di un altro errore; sckConnectionReset: corrispondente al valore 10054. Indica che la connessione è stata reinviata dal computer remoto; sckNoBufferSpace: corrispondente al valore 10055. Indica che lo spazio nel buffer è esaurito; sckAlreadyConnected: corrispondente al valore 10056. Indica che la connessione è già stata stabilita; sckSocketShutdown: corrispondente al valore 10058. Indica che la connessione è già stata chiusa; sckTimedout: corrispondente al valore 10068. Indica che la connessione è stata chiusa; sckConnectionRefused: corrispondente al valore 10061. Indica che la connessione è stata rifiutata dal computer server; sckNotInitalized: corrispondente al valore 10093. Indica che è necessario richiamare WinsockInit per primo; sckHostNotFound: corrispondente al valore 11001. Indica che è impossibile trovare l'host in modo definitivo; sckInvalidArgument: corrispondente al valore 11002. Indica che è impossibile trovare l'host; sckNotRecoverableError: corrispondente al valore 11003. Indica un errore non riconoscibile; sckNoData: corrispondente al valore 11004. Indica che non è possibile ricevere nessun dato del tipo richiesto (quando si fa uso della specifica Winsock.GetData (tipo); Evento SendComplete : viene generato quando tutti i dati sono stati inviati con successo; Evento SendProgress : viene generato quando il processo di invio dei dati è ancora in corso.

 

3: Primi passi nella stesura dell'applicazione. Primi passi nella stesura dell’applicazione Per cominciare aprire un nuovo progetto EXE Standard. Selezionare quindi la voce 'Componenti' dal menu 'Progetto'. Apparirà dunque la finestra denominata 'Componenti'. Nella lista che presenta, contrassegnare col segno di spunta la casella relativa alla voce 'Microsoft Winsock Control x.0' dove la x rappresenta la versione disponibile sul proprio computer. Come si è già detto, e com'è possibile intuire dal messaggio ricevuto dalla finestra 'Componenti', è necessaria la presenza sul proprio computer del file MSWINSCK.OCX. Nel caso in cui detto file non si trovi nella classica cartella "C:\WINDOWS\SYSTEM", premere il pulsante 'Sfoglia' della finestra 'Componenti' per ricercare la posizione effettiva nella quale è situato il file.

 

 

 

Figura 1

Dando l'OK alla finestra dovrebbe apparire, tra i controlli disponibili sulla sinistra della finestra di lavoro di Visual Basic, il pulsante recante la tipica icona di Winsock, proprio come mostrato dalla Figura 2. Questo indica che il controllo è pronto ad essere utilizzato e trascinato sul piano, senza però la possibilità di ridimensionarlo a piacimento.

Figura 2

Per simulare ciò che abbiamo fatto dal Prompt di DOS, dobbiamo rendere il nostro computer sia Client che Server, permettendogli di richiedere e scambiare dati con se stesso. A tale scopo, possiamo pensare di rinominare Form1 come frmServer, cosa che ci ricorderà in maniera semplice che l'interfaccia ed il codice sviluppati per quella form sono relative alla funzione Server del computer. Aggiungiamo quindi a frmServer alcuni controlli. Saranno sufficienti due controlli TextBox (le caselle di testo) ed un CommandButton (il pulsante). Dato che, come abbiamo visto, il server deve stare sempre in ascolto di eventuali richieste di comunicazione che possono pervenire da altri computer, istruiamo Winsock a compiere tale operazione sulla porta 100 all'apertura dell'applicazione, ossia nell'evento Load di frmServer:

Private Sub

Winsock1.LocalPort = 100 Winsock1.Listen End Sub

Notare che il valore assegnato a LocalPort può essere un qualsiasi intero. Il computer client deve però essere a conoscenza della porta sulla quale il server è in attesa. In caso contrario non ci sarà alcuna risposta ad eventuali richieste di connessione. Nel caso dell'applicazione che stiamo sviluppando, risulta particolarmente semplice mettere d'accordo client e server sulla porta comune da utilizzare, in quanto essi coesistono sullo stesso computer. Abbiamo visto l'evento Load di frmServer. Adesso addentriamoci negli eventi più propriamente legati al controllo Winsock. Innanzitutto istruiamo l'applicazione nel caso in cui si verifichi una richiesta di connessione da parte del client sulla porta comune (in questo caso la 100). Sarà necessario chiudere un'eventuale precedente connessione del server prima di accettare la nuova richiesta da parte del client. Per far ciò, dobbiamo controllare la proprietà State di Winsock. Tra tutti gli stati che Winsock può assumere, scegliamo 'Chiuso' e facciamo un ragionamento del tipo: se lo stato di Winsock è 'chiuso', allora vuol dire che non è in comunicazione con nessun computer client. In questo caso si può accettare una nuova richiesta. In caso contrario (comunicazione pendente, aperta, invio dati...) lo stato di Winsock deve tornare 'chiuso'. Traduciamo il tutto con questo blocco di codice:

Private Sub ByVal As Long If Then

End If

Notare che è stato assegnato al controllo Winsock il nome tcpServer. Questo accorgimento può risultare
utile a distinguere il controllo Winsock utilizzato nella form Server e quello nella form Client.
Quando si arriverà a sviluppare il secondo blocco, sarà infatti necessario includere un secondo controllo
Winsock, denominato questa volta tcpClient.

Nulla vieta, tuttavia, di mantenere i nomi originali dei controlli ossia Winsock1 e Winsock2. A tale blocco, però, manca ancora qualcosa: nel caso di richiesta di comunicazione da parte di un computer client, infatti, si farà in modo di accettare tale richiesta. Una volta giunti a questa linea di codice, la comunicazione si può considerare avviata. Il blocco di codice visto poco sopra, integrato con la linea di codice di cui si parlava, apparirà in questo modo:

Private Sub tcpServer_ConnectionRequest(ByVal requestID As Long)

If tcpServer.State <> sckClosed Then
tcpServer.Close
End If

tcpServer.Accept RequestID End Sub

Adesso dobbiamo istruire il controllo sulle operazioni da eseguire in caso di richiesta da parte del client oppure in caso di invio dei dati. Pensiamo innanzitutto alla prima eventualità. Quando arrivano dati dal computer client, infatti, viene richiamato il metodo DataArrival. Prima di vedere il codice, studiamo la cronologia degli eventi associati a questo caso: s'immagini di avere due computer separati. L'utente del computer A è intenzionato ad entrare in comunicazione col computer B. Nel momento in cui l'utente di A preme il tasto che avvia la comunicazione, il suo computer compie una breve ricerca sulle informazioni che lo identificano (ID, nome del computer). Una volta terminata questa operazione, finalmente la comunicazione viene avviata ed i primi dati inviati dal client al server sono quelli di riconoscimento del computer che fa la richiesta (è un po' come chiamare una persona al telefono e, prima di iniziare un discorso, presentarsi ed eventualmente fornire ulteriori informazioni come il nome dell'azienda per conto della quale si telefona e così via). Ecco perchè abbiamo incluso la linea di codice:

tcpServer.Accept RequestID

Dopodiché, tutte le informazioni inviate dal computer A vengono incluse in una variabile dell'applicazione del computer B che chiamiamo strData, inizialmente vuota, che andrà finalmente a riempire la casella di testo che abbiamo precedentemente inserito nella form. E' come se colui che riceve la telefonata si preoccupi di annotare su un foglio, ancor prima di cominciare la comunicazione vera e propria, l'identità di chi è dall'altra parte del telefono. Tradotto in codice quanto appena detto, ci troviamo di fronte a questo risultato:

Private Sub tcpServer_DataArrival(ByVal bytesTotal As Long)

Dim strData As String

tcpServer.GetData striata
Text1.Text = striata

End Sub

Prima di continuare è necessario fare un'importante precisazione, ossia che il metodo GetData del controllo Winsock (o tcpServer nel nostro caso) svuota automaticamente la variabile strData con le informazioni del computer client dopo averle inviate alla casella di testo Text1. Per evitare ciò, si può far ricorso alla proprietà PeekData. Per concludere, manca il codice relativo all'invio dei dati da parte del server, invio che viene effettuato mediante la pressione del tasto Command1 che avevamo inserito sul piano. I dati inviati corrispondono al contenuto di una casella di testo che possiamo chiamare Text2. La procedura da seguire in questo caso è davvero molto semplice e non necessita di grossi chiarimenti. Semplicemente, alla pressione del tasto, il controllo Winsock fa uso della proprietà SendData che invia i dati al client:

Private Sub Command1_Click()

tcpServer.SendData Text2.Text

End Sub